package spider

//import (
//	"errors"
//	"fmt"
//	"github.com/apex/log"
//	"github.com/crawlab-team/crawlab-core/constants"
//	"github.com/crawlab-team/crawlab-core/entity"
//	"github.com/crawlab-team/crawlab-core/lib/cron"
//	"github.com/crawlab-team/crawlab-core/models"
//	"github.com/crawlab-team/crawlab-core/services/spider_handler"
//	"github.com/crawlab-team/crawlab-core/utils"
//	database "github.com/crawlab-team/crawlab-db"
//	"github.com/globalsign/mgo"
//	"github.com/globalsign/mgo/bson"
//	"github.com/satori/go.uuid"
//	"github.com/spf13/viper"
//	"gopkg.in/yaml.v2"
//	"io"
//	"io/ioutil"
//	"os"
//	"path"
//	"path/filepath"
//	"runtime/debug"
//	"time"
//)
//
//type SpiderFileData struct {
//	FileName string
//	File     []byte
//}
//
//type SpiderUploadMessage struct {
//	FileId   string
//	FileName string
//	SpiderId string
//}
//
//// 从主节点上传爬虫到GridFS
//func UploadSpiderToGridFsFromMaster(spider model.Spider) error {
//	// 爬虫所在目录
//	spiderDir := spider.Src
//
//	// 打包为 zip 文件
//	files, err := utils.GetFilesFromDir(spiderDir)
//	if err != nil {
//		return err
//	}
//	randomId := uuid.NewV4()
//	tmpFilePath := filepath.Join(viper.GetString("other.tmppath"), spider.Name+"."+randomId.String()+".zip")
//	spiderZipFileName := spider.Name + ".zip"
//	if err := utils.Compress(files, tmpFilePath); err != nil {
//		return err
//	}
//
//	// 获取 GridFS 实例
//	s, gf := database.GetGridFs("files")
//	defer s.Close()
//
//	// 判断文件是否已经存在
//	var gfFile model.GridFs
//	if err := gf.Find(bson.M{"filename": spiderZipFileName}).One(&gfFile); err == nil {
//		// 已经存在文件，则删除
//		log.Errorf(gfFile.Id.Hex() + " already exists. removing...")
//		if err := gf.RemoveId(gfFile.Id); err != nil {
//			log.Errorf(err.Error())
//			debug.PrintStack()
//			return err
//		}
//	}
//
//	// 上传到GridFs
//	fid, err := RetryUploadToGridFs(spiderZipFileName, tmpFilePath)
//	if err != nil {
//		log.Errorf("upload to grid fs error: %s", err.Error())
//	}
//
//	// 保存爬虫 FileId
//	spider.FileId = fid
//	if err := spider.Save(); err != nil {
//		return err
//	}
//
//	// 获取爬虫同步实例
//	spiderSync := spider_handler.SpiderSync{
//		Spider: spider,
//	}
//
//	// 获取gfFile
//	gfFile2 := model.GetGridFs(spider.FileId)
//
//	// 生成MD5
//	spiderSync.CreateMd5File(gfFile2.Md5)
//
//	// 检查是否为 Scrapy 爬虫
//	spiderSync.CheckIsScrapy()
//
//	return nil
//}
//
//// 上传zip文件到GridFS
//func UploadToGridFs(fileName string, filePath string) (fid bson.ObjectId, err error) {
//	fid = ""
//
//	// 获取MongoDB GridFS连接
//	s, gf := database.GetGridFs("files")
//	defer s.Close()
//
//	// 创建一个新GridFS文件
//	f, err := gf.Create(fileName)
//	if err != nil {
//		log.Errorf("create file error: " + err.Error())
//		debug.PrintStack()
//		return
//	}
//
//	// 分片读取爬虫zip文件
//	err = ReadFileByStep(filePath, WriteToGridFS, f)
//	if err != nil {
//		log.Errorf("read file by step error: " + err.Error())
//		debug.PrintStack()
//		return "", err
//	}
//
//	// 删除zip文件
//	if err = os.Remove(filePath); err != nil {
//		log.Errorf("remove file error: " + err.Error())
//		debug.PrintStack()
//		return
//	}
//
//	// 关闭文件，提交写入
//	if err = f.Close(); err != nil {
//		log.Errorf("close file error: " + err.Error())
//		debug.PrintStack()
//		return "", err
//	}
//
//	// 文件ID
//	fid = f.Id().(bson.ObjectId)
//
//	return fid, nil
//}
//
//// 带重试功能的上传至 GridFS
//func RetryUploadToGridFs(fileName string, filePath string) (fid bson.ObjectId, err error) {
//	maxErrCount := 10
//	errCount := 0
//	for {
//		if errCount > maxErrCount {
//			break
//		}
//		fid, err = UploadToGridFs(fileName, filePath)
//		if err != nil {
//			errCount++
//			log.Errorf("upload to grid fs error: %s", err.Error())
//			time.Sleep(3 * time.Second)
//			continue
//		}
//		return fid, nil
//	}
//	return fid, errors.New("unable to upload to gridfs, please re-upload the spider")
//}
//
//// 写入grid fs
//func WriteToGridFS(content []byte, f *mgo.GridFile) {
//	if _, err := f.Write(content); err != nil {
//		debug.PrintStack()
//		return
//	}
//}
//
////分片读取大文件
//func ReadFileByStep(filePath string, handle func([]byte, *mgo.GridFile), fileCreate *mgo.GridFile) error {
//	f, err := os.OpenFile(filePath, os.O_RDONLY, 0777)
//	if err != nil {
//		log.Infof("can't opened this file")
//		return err
//	}
//	defer utils.Close(f)
//	s := make([]byte, 4096)
//	for {
//		switch nr, err := f.Read(s[:]); true {
//		case nr < 0:
//			_, _ = fmt.Fprintf(os.Stderr, "cat: error reading: %s\n", err.Error())
//			debug.PrintStack()
//		case nr == 0: // EOF
//			return nil
//		case nr > 0:
//			handle(s[0:nr], fileCreate)
//		}
//	}
//}
//
//// 发布所有爬虫
//func PublishAllSpiders() {
//	// 获取爬虫列表
//	spiders, _, _ := model.GetSpiderList(nil, 0, constants.Infinite, "-_id")
//	if len(spiders) == 0 {
//		return
//	}
//	log.Infof("start sync spider to local, total: %d", len(spiders))
//	// 遍历爬虫列表
//	for _, spider := range spiders {
//		// 异步发布爬虫
//		go func(s model.Spider) {
//			PublishSpider(s)
//		}(spider)
//	}
//}
//
//// 发布爬虫
//func PublishSpider(spider model.Spider) {
//	var gfFile *model.GridFs
//	if spider.FileId.Hex() != constants.ObjectIdNull {
//		// 查询gf file，不存在则标记为爬虫文件不存在
//		gfFile = model.GetGridFs(spider.FileId)
//		if gfFile == nil {
//			log.Errorf("get grid fs file error: cannot find grid fs file")
//			log.Errorf("grid fs file_id: " + spider.FileId.Hex())
//			log.Errorf("spider_name: " + spider.Name)
//			debug.PrintStack()
//			//spider.FileId = constants.ObjectIdNull
//			//if err := spider.Save(); err != nil {
//			//	return
//			//}
//			return
//		}
//	}
//
//	// 如果FileId为空，表示还没有上传爬虫到GridFS，则跳过
//	if spider.FileId == bson.ObjectIdHex(constants.ObjectIdNull) {
//		return
//	}
//
//	// 获取爬虫同步实例
//	spiderSync := spider_handler.SpiderSync{
//		Spider: spider,
//	}
//
//	// 安装依赖
//	if viper.GetString("setting.autoInstall") == "Y" {
//		go spiderSync.InstallDeps()
//	}
//
//	//目录不存在，则直接下载
//	path := filepath.Join(viper.GetString("spider.path"), spider.Name)
//	if !utils.Exists(path) {
//		log.Infof("path not found: %s", path)
//		spiderSync.Download()
//		spiderSync.CreateMd5File(gfFile.Md5)
//		spiderSync.CheckIsScrapy()
//		return
//	}
//
//	// md5文件不存在，则下载
//	md5 := filepath.Join(path, spider_handler.Md5File)
//	if !utils.Exists(md5) {
//		log.Infof("md5 file not found: %s", md5)
//		spiderSync.RemoveDownCreate(gfFile.Md5)
//		return
//	}
//
//	// md5值不一样，则下载
//	md5Str := utils.GetSpiderMd5Str(md5)
//	if gfFile.Md5 != md5Str {
//		log.Infof("md5 is different, gf-md5:%s, file-md5:%s", gfFile.Md5, md5Str)
//		spiderSync.RemoveDownCreate(gfFile.Md5)
//		return
//	}
//}
//
//func RemoveSpider(id string) error {
//	// 获取该爬虫
//	spider, err := model.GetSpider(bson.ObjectIdHex(id))
//	if err != nil {
//		return err
//	}
//
//	// 删除爬虫文件目录
//	path := filepath.Join(viper.GetString("spider.path"), spider.Name)
//	utils.RemoveFiles(path)
//
//	// 删除其他节点的爬虫目录
//	//msg := entity.NodeMessage{
//	//	Type:     constants.MsgTypeRemoveSpider,
//	//	SpiderId: id,
//	//}
//	//if err := database.Pub(constants.ChannelAllNode, msg); err != nil {
//	//	return err
//	//}
//
//	// 从数据库中删除该爬虫
//	if err := model.RemoveSpider(bson.ObjectIdHex(id)); err != nil {
//		return err
//	}
//
//	// 删除爬虫对应的task任务
//	if err := model.RemoveTaskBySpiderId(spider.Id); err != nil {
//		return err
//	}
//
//	// TODO 定时任务如何处理
//	return nil
//}
//
//func CancelSpider(id string) error {
//	// 获取该爬虫
//	spider, err := model.GetSpider(bson.ObjectIdHex(id))
//	if err != nil {
//		return err
//	}
//
//	// 获取该爬虫待定或运行中的任务列表
//	query := bson.M{
//		"spider_id": spider.Id,
//		"status": bson.M{
//			"$in": []string{
//				constants.StatusPending,
//				constants.StatusRunning,
//			},
//		},
//	}
//	tasks, err := model.GetTaskList(query, 0, constants.Infinite, "-create_ts")
//	if err != nil {
//		return err
//	}
//
//	// 遍历任务列表，依次停止
//	for _, task := range tasks {
//		if err := CancelTask(task.Id); err != nil {
//			return err
//		}
//	}
//
//	return nil
//}
//
//func cloneGridFsFile(spider model.Spider, newName string) (err error) {
//	// 构造新爬虫
//	newSpider := spider
//	newSpider.Id = bson.NewObjectId()
//	newSpider.Name = newName
//	newSpider.DisplayName = newName
//	newSpider.Src = path.Join(path.Dir(spider.Src), newName)
//	newSpider.CreateTs = time.Now()
//	newSpider.UpdateTs = time.Now()
//
//	// GridFS连接实例
//	s, gf := database.GetGridFs("files")
//	defer s.Close()
//
//	// 被克隆爬虫的GridFS文件
//	f, err := gf.OpenId(spider.FileId)
//	if err != nil {
//		log.Errorf(err.Error())
//		debug.PrintStack()
//		return err
//	}
//
//	// 新爬虫的GridFS文件
//	fNew, err := gf.Create(newSpider.Name + ".zip")
//	if err != nil {
//		log.Errorf(err.Error())
//		debug.PrintStack()
//		return err
//	}
//
//	// 生成唯一ID
//	randomId := uuid.NewV4()
//	tmpPath := viper.GetString("other.tmppath")
//	if !utils.Exists(tmpPath) {
//		if err := os.MkdirAll(tmpPath, 0777); err != nil {
//			log.Errorf("mkdir other.tmppath error: %v", err.Error())
//			return err
//		}
//	}
//
//	// 创建临时文件
//	tmpFilePath := filepath.Join(tmpPath, randomId.String()+".zip")
//	tmpFile := utils.OpenFile(tmpFilePath)
//
//	// 拷贝到临时文件
//	if _, err := io.Copy(tmpFile, f); err != nil {
//		log.Errorf(err.Error())
//		debug.PrintStack()
//		return err
//	}
//
//	// 关闭临时文件
//	if err := tmpFile.Close(); err != nil {
//		log.Errorf(err.Error())
//		debug.PrintStack()
//		return err
//	}
//
//	// 读取内容
//	fContent, err := ioutil.ReadFile(tmpFilePath)
//	if err != nil {
//		log.Errorf(err.Error())
//		debug.PrintStack()
//		return err
//	}
//
//	// 写入GridFS文件
//	if _, err := fNew.Write(fContent); err != nil {
//		log.Errorf(err.Error())
//		debug.PrintStack()
//		return err
//	}
//
//	// 关闭被克隆爬虫GridFS文件
//	if err = f.Close(); err != nil {
//		log.Errorf(err.Error())
//		debug.PrintStack()
//		return err
//	}
//
//	// 将新爬虫文件复制
//	newSpider.FileId = fNew.Id().(bson.ObjectId)
//
//	// 保存新爬虫
//	if err := newSpider.Add(); err != nil {
//		return err
//	}
//
//	// 关闭新爬虫GridFS文件
//	if err := fNew.Close(); err != nil {
//		log.Errorf(err.Error())
//		debug.PrintStack()
//		return err
//	}
//
//	// 删除临时文件
//	if err := os.RemoveAll(tmpFilePath); err != nil {
//		log.Errorf(err.Error())
//		debug.PrintStack()
//		return err
//	}
//
//	// 同步爬虫
//	PublishSpider(newSpider)
//
//	return nil
//}
//
//func CopySpider(spider model.Spider, newName string) error {
//	// 克隆GridFS文件
//	if err := cloneGridFsFile(spider, newName); err != nil {
//		return err
//	}
//
//	return nil
//}
//
//func UpdateSpiderDedup(spider model.Spider) error {
//	col := utils.GetSpiderCol(spider.Col, spider.Name)
//
//	s, c := database.GetCol(col)
//	defer s.Close()
//
//	if !spider.IsDedup {
//		_ = c.DropIndex(spider.DedupField)
//		//if err := c.DropIndex(spider.DedupField); err != nil {
//		//	return err
//		//}
//		return nil
//	}
//
//	if err := c.EnsureIndex(mgo.Index{
//		Key:    []string{spider.DedupField},
//		Unique: true,
//	}); err != nil {
//		return err
//	}
//
//	return nil
//}
//
//func InitDemoSpiders() {
//	// 添加Demo爬虫
//	templateSpidersDir := "./template/spiders"
//	for _, info := range utils.ListDir(templateSpidersDir) {
//		if !info.IsDir() {
//			continue
//		}
//		spiderName := info.Name()
//
//		// 如果爬虫在数据库中不存在，则添加
//		spider := model.GetSpiderByName(spiderName)
//		if spider.Name != "" {
//			// 存在同名爬虫，跳过
//			continue
//		}
//
//		// 拷贝爬虫
//		templateSpiderPath := path.Join(templateSpidersDir, spiderName)
//		spiderPath := path.Join(viper.GetString("spider.path"), spiderName)
//		if utils.Exists(spiderPath) {
//			utils.RemoveFiles(spiderPath)
//		}
//		if err := utils.CopyDir(templateSpiderPath, spiderPath); err != nil {
//			log.Errorf("copy error: " + err.Error())
//			debug.PrintStack()
//			continue
//		}
//
//		// 构造配置数据
//		configData := entity.ConfigSpiderData{}
//
//		// 读取YAML文件
//		yamlFile, err := ioutil.ReadFile(path.Join(spiderPath, "Spiderfile"))
//		if err != nil {
//			log.Errorf("read yaml error: " + err.Error())
//			//debug.PrintStack()
//			continue
//		}
//
//		// 反序列化
//		if err := yaml.Unmarshal(yamlFile, &configData); err != nil {
//			log.Errorf("unmarshal error: " + err.Error())
//			debug.PrintStack()
//			continue
//		}
//
//		if configData.Type == constants.Customized {
//			// 添加该爬虫到数据库
//			spider = model.Spider{
//				Id:          bson.NewObjectId(),
//				Name:        spiderName,
//				DisplayName: configData.DisplayName,
//				Type:        constants.Customized,
//				Col:         configData.Col,
//				Src:         spiderPath,
//				Remark:      configData.Remark,
//				ProjectId:   bson.ObjectIdHex(constants.ObjectIdNull),
//				FileId:      bson.ObjectIdHex(constants.ObjectIdNull),
//				Cmd:         configData.Cmd,
//				UserId:      bson.ObjectIdHex(constants.ObjectIdNull),
//			}
//			if err := spider.Add(); err != nil {
//				log.Errorf("add spider error: " + err.Error())
//				debug.PrintStack()
//				continue
//			}
//
//			// 上传爬虫到GridFS
//			if err := UploadSpiderToGridFsFromMaster(spider); err != nil {
//				log.Errorf("upload spider error: " + err.Error())
//				debug.PrintStack()
//				continue
//			}
//		} else if configData.Type == constants.Configurable || configData.Type == "config" {
//			// 添加该爬虫到数据库
//			spider = model.Spider{
//				Id:          bson.NewObjectId(),
//				Name:        configData.Name,
//				DisplayName: configData.DisplayName,
//				Type:        constants.Configurable,
//				Col:         configData.Col,
//				Src:         spiderPath,
//				Remark:      configData.Remark,
//				ProjectId:   bson.ObjectIdHex(constants.ObjectIdNull),
//				FileId:      bson.ObjectIdHex(constants.ObjectIdNull),
//				Config:      configData,
//				UserId:      bson.ObjectIdHex(constants.ObjectIdNull),
//			}
//			if err := spider.Add(); err != nil {
//				log.Errorf("add spider error: " + err.Error())
//				debug.PrintStack()
//				continue
//			}
//
//			// 根据序列化后的数据处理爬虫文件
//			if err := ProcessSpiderFilesFromConfigData(spider, configData); err != nil {
//				log.Errorf("add spider error: " + err.Error())
//				debug.PrintStack()
//				continue
//			}
//		}
//	}
//
//	// 发布所有爬虫
//	PublishAllSpiders()
//}
//
//// 启动爬虫服务
//func InitSpiderService() error {
//	// 构造定时任务执行器
//	cPub := cron.New(cron.WithSeconds())
//	if _, err := cPub.AddFunc("0 * * * * *", PublishAllSpiders); err != nil {
//		return err
//	}
//
//	// 启动定时任务
//	cPub.Start()
//
//	if model.IsMaster() && viper.GetString("setting.demoSpiders") == "Y" {
//		// 初始化Demo爬虫
//		InitDemoSpiders()
//	}
//
//	if model.IsMaster() {
//		// 构造 Git 定时任务
//		GitCron = &GitCronScheduler{
//			cron: cron.New(cron.WithSeconds()),
//		}
//
//		// 启动 Git 定时任务
//		if err := GitCron.Start(); err != nil {
//			return err
//		}
//
//		// 清理UserId
//		InitSpiderCleanUserIds()
//	}
//
//	return nil
//}
